package xwc.usertree;

import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import xwc.usertree.exceptions.AccountNotFoundException;
import xwc.usertree.exceptions.NewAccountException;

import java.math.BigDecimal;
import java.util.*;

/**
 * 整个树在内存中维护一份，重启时从数据库account表恢复树。也可以直接把account保存到数据库中
 */
@Slf4j
public class AccountTree {
    private Account rootNode; // 根节点，是系统，不是具体用户
    private IStoreStrategy storeStrategy = new MemoryStoreStrategy(); // 保存策略

    public AccountTree() {
        this.rootNode = new Account();
    }

    public Account getRootNode() {
        return rootNode;
    }

    public void setRootNode(Account rootNode) {
        this.rootNode = rootNode;
    }

    public synchronized Account findInTreeByKey(String key) {
        Account account;
        if (key == null) {
            account = rootNode;
        } else {
            account = rootNode.findInTreeByKey(key);
            if (account == null) {
                return null;
            }
        }
        return account;
    }

    private List<TreeTransaction> activeTransactions = new ArrayList<>();

    public synchronized TreeTransaction createTransaction() {
        TreeTransaction tx = new TreeTransaction(this);
        activeTransactions.add(tx);
        return tx;
    }

    public synchronized void removeTransaction(TreeTransaction tx) {
        if (tx != null) {
            activeTransactions.remove(tx);
        }
    }

    // private or call by tests
    public void setNodeParentByChildrenInTree(Account account) {
        if (account.getChildren() == null) {
            return;
        }
        for (Account child : account.getChildren()) {
            child.setParent(account);
            setNodeParentByChildrenInTree(child);
        }
    }

    public synchronized void rollbackToSnapshot(TreeSnapshot snapshot) {
        Account newRootNode = JSON.toJavaObject(snapshot.getRootNodeJSON(), Account.class);
        // 根据children设置parent等未序列化的属性
        setNodeParentByChildrenInTree(newRootNode);
        this.rootNode = newRootNode;
    }

    public static synchronized AccountTree create(List<Account> allNodes) throws NewAccountException, AccountNotFoundException {
        AccountTree tree = new AccountTree();
        int addedAccountsCount = 0; // 已经添加到树中的数量
        int addingLevel = 1; // 正在添加哪层的节点
        List<Account> notAddedNodes = new ArrayList<>(allNodes);
        Map<String, Integer> addedAccountKeys = new HashMap<>(); // accountKey => level
        // 依次找到所有第1层-第n层的各节点
        int recyleCount = 0;
        TreeTransaction tx = tree.createTransaction();
        try {
            while (true) {
                if (notAddedNodes.isEmpty()) {
                    break; // 添加完成
                }
                if (recyleCount > 1000000) {
                    throw new RuntimeException("create account tree loop loop exceed");
                }
                recyleCount++;
                List<Account> addedNodesInThisLevel = new ArrayList<>();
                for (Account node : notAddedNodes) {
                    if (addingLevel <= 1) {
                        // 正在添加第一层节点
                        if (node.getParentKey() == null) {
                            tree.addNewAccount(tx, node.getKey(), node.getPhone(), node.getParentKey(), BigDecimal.ZERO, BigDecimal.ZERO);
                            addedAccountsCount++;
                            addedAccountKeys.put(node.getKey(), addingLevel);
                            addedNodesInThisLevel.add(node);
                        }
                    } else {
                        if (node.getParentKey() != null && addedAccountKeys.containsKey(node.getParentKey())) {
                            int nodeLevel = addedAccountKeys.get(node.getParentKey()) + 1;
                            tree.addNewAccount(tx, node.getKey(), node.getPhone(), node.getParentKey(), BigDecimal.ZERO, BigDecimal.ZERO);
                            addedAccountsCount++;
                            addedAccountKeys.put(node.getKey(), nodeLevel);
                            addedNodesInThisLevel.add(node);
                        }
                    }
                }
                notAddedNodes.removeAll(addedNodesInThisLevel);
                addingLevel++;
            }
            for (Account node : allNodes) {
                tree.setAccountInfo(node);
            }
            tx.commit();
        } catch (Exception e) {
            log.error("创建内存树结构发生异常：{}", e);
            tx.rollback();
        }
        return tree;
    }


    /**
     * 强制设置account的基本信息，用于重启时强制设置整棵数
     *
     * @param account
     */
    public synchronized void setAccountInfo(Account account) throws AccountNotFoundException {
        Account item = findInTreeByKey(account.getKey());
        if (item == null) {
            throw new AccountNotFoundException("can't find account " + account.getKey());
        }
        if (account.getDepositedTotal() != null) {
            item.setDepositedTotal(account.getDepositedTotal());
        }
        if (account.getDividendPool() != null) {
            item.setDividendPool(account.getDividendPool());
        }
        if (account.getLevel() != null) {
            item.setLevel(account.getLevel());
        }
        if (account.getCurrentRecommenderRewardArr() != null) {
            item.setCurrentRecommenderRewardArr(account.getCurrentRecommenderRewardArr());
        }
        if (account.getNewChildCountInCurrentDeposit() != null) {
            item.setNewChildCountInCurrentDeposit(account.getNewChildCountInCurrentDeposit());
        }
        if (account.getParentKey() != null) {
            item.setParentKey(account.getParentKey());
        }
        storeStrategy.saveAccounts(item);
    }

    public synchronized void setAccountInfo(String accountKey, BigDecimal depositedTotal, BigDecimal dividendPool, Integer level,
                                            Integer newChildCountInCurrentDeposit, String parentKey) throws AccountNotFoundException {
        Account account = new Account();
        account.setKey(accountKey);
        account.setDepositedTotal(depositedTotal);
        account.setDividendPool(dividendPool);
        account.setLevel(level);
        account.setNewChildCountInCurrentDeposit(newChildCountInCurrentDeposit);
        account.setParentKey(parentKey);
        setAccountInfo(account);
    }

    /**
     * 重新设置所有节点的account level
     */
    public synchronized void autoSetAllAccountsLevels() {
        rootNode.visitTreeFromDownToTop(account -> {
            BigDecimal subTotalDeposited = account.countTotalChildrenDepositedTotal();
            if (account.getChildren().size() < Config.v1MinChildrenCount) {
                account.setLevel(0);
            } else {
                int level = AccountLevels.getLevelOfTotalChildrenDeposited(account, subTotalDeposited);
                account.setLevel(level);
            }
        });
    }

    @AllArgsConstructor
    @Getter
    @Setter
    public static class AccountIncome {
        private Account account;
        private Income income;

        @Override
        public String toString() {
            return "AccountIncome{" +
                    "account=" + account.getKey() +
                    ", income=" + income +
                    '}';
        }
    }


    /**
     * onAddNewAccount的时候不激活这个账户，也就是不给parentAccount.childCount自增。另外调用activeNewAccount的时候(第一次充值时激活)才激活并增加parentAccount.childCount
     */
    public synchronized Pair<List<Account>, List<AccountIncome>> activateNewAccount(TreeTransaction tx, String accountKey, BigDecimal originalOrePool, BigDecimal depositAmount,
                                                                                    BigDecimal intoDividendPoolAmount) throws AccountNotFoundException {
        if (accountKey == null) {
            throw new AccountNotFoundException("invalid account key");
        }
        TreeSnapshot snapshot = tx.getSnapshot();
        List<Account> changedAccounts = new ArrayList<>();
        List<AccountIncome> incomes = new ArrayList<>();
        Account account = findInTreeByKey(accountKey);
        if (account == null) {
            throw new AccountNotFoundException("account " + accountKey + " not found");
        }
        log.info("activateNewAccount({} {}, {}, {}, {})", account.getKey(), account.getPhone(),
                originalOrePool, depositAmount, intoDividendPoolAmount);
        Account parentAccount = findInTreeByKey(account.getParentKey());
        if (parentAccount == null) {
            throw new AccountNotFoundException("parent account " + account.getParentKey() + " not found");
        }
        //children累积充值数量加1
        parentAccount.setNewChildCountInCurrentDepositWithSnapshot(snapshot, parentAccount.getNewChildCountInCurrentDeposit() + 1);
//        parentAccount.setLevel(AccountLevels.getLevelOfTotalChildrenDeposited(parentAccount, parentAccount.countTotalChildrenDepositedTotal()));
        changedAccounts.add(account);
        changedAccounts.add(parentAccount);

        // 因为拉到新下级而释放个人分红池
        BigDecimal maxFree = AccountLevels.getParentFreeAmountWhenNewChild(parentAccount, depositAmount);
        if (parentAccount.getDividendPool().compareTo(maxFree) < 0) {
            maxFree = parentAccount.getDividendPool();
        }

        getAddNewDepositStaticIncomes(tx, changedAccounts, incomes, accountKey, originalOrePool, depositAmount, intoDividendPoolAmount);
        if (maxFree.compareTo(BigDecimal.ZERO) > 0) {
            //添加直接推荐奖励的记录
            parentAccount.addRecommenderReward(new BigDecimal[]{maxFree});
            //设置矿池金额
            parentAccount.setDividendPoolWithSnapshot(snapshot, parentAccount.getDividendPool().subtract(maxFree));
            // 新下线充值时部分金额作为额度给上级释放分红池
            log.info("free parent ore pool by activate new account");
            addAccountIncome(incomes, parentAccount, maxFree, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
        } else {
            log.info("activateNewAccount. userId:{}, maxFree:{}, incomes is empty", accountKey, maxFree);
        }

//        applyStaticIncomes(tx, changedAccounts, incomes);

        storeStrategy.saveAccounts(changedAccounts);

        return Pair.of(changedAccounts, incomes);
    }


    /**
     * 账户第一次入金时触发
     *
     * @param accountKey             新账户id
     * @param parentKey              推荐人id
     * @param depositAmount          新账户本次入金金额
     * @param intoDividendPoolAmount 入金金额对应的矿池金额
     * @return changedAccounts   left: 影响的账户列表，包括vip级别等信息, right: 影响的各账户的收益列表
     */
    public synchronized Pair<List<Account>, List<AccountIncome>> addNewAccount(TreeTransaction tx,
                                                                               String accountKey, String phone, String parentKey, BigDecimal depositAmount,
                                                                               BigDecimal intoDividendPoolAmount) throws NewAccountException, AccountNotFoundException {
        log.info("addNewAccount({}, {}, {}, {}, {})", accountKey, phone, parentKey, depositAmount, intoDividendPoolAmount);
        if (accountKey == null) {
            throw new NewAccountException("invalid account key");
        }
        TreeSnapshot snapshot = tx.getSnapshot();
        List<Account> changedAccounts = new ArrayList<>();
        Account newAccount = findInTreeByKey(accountKey);
        if (newAccount != null) {
            throw new NewAccountException("account " + accountKey + " existed");
        }
        Account parentAccount = findInTreeByKey(parentKey);
        if (parentAccount == null) {
            throw new NewAccountException("parent account " + parentKey + " not found");
        }
        newAccount = new Account();
        newAccount.setParentKeyWithSnapshot(snapshot, parentAccount.getKey());
        newAccount.setParentWithSnapshot(snapshot, parentAccount);
        newAccount.setKeyWithSnapshot(snapshot, accountKey);
        newAccount.setPhoneWithSnapshot(snapshot, phone);

        changedAccounts.add(newAccount);

        snapshot.addNewAccount(newAccount);
        parentAccount.addChildWithSnapshot(snapshot, newAccount);
//        parentAccount.setNewChildCountInCurrentDeposit(parentAccount.getNewChildCountInCurrentDeposit() + 1);
//        parentAccount.setLevel(AccountLevels.getLevelOfTotalChildrenDeposited(parentAccount.countTotalChildrenDepositedTotal()));

        changedAccounts.add(parentAccount);

        storeStrategy.saveAccounts(newAccount, parentAccount);


        List<AccountIncome> incomes = new ArrayList<>();

        return Pair.of(changedAccounts, incomes);
    }

    private AccountIncome findAccountIncome(List<AccountIncome> incomes, Account account) {
        for (AccountIncome item : incomes) {
            if (item.account == account || item.account.getKey().equals(account.getKey())) {
                return item;
            }
        }
        return null;
    }

    private AccountIncome addAccountIncome(List<AccountIncome> incomes, Account account, BigDecimal deltaDirectIncome,
                                           BigDecimal deltaStaticIncome, BigDecimal deltaDynamicIncome, BigDecimal deltaGenerationIncome) {
        log.info("account {} {} add incomes: direct {}, static: {}, dynamic: {}, generation: {}",
                account.getKey(), account.getPhone(),
                deltaDirectIncome, deltaStaticIncome, deltaDynamicIncome, deltaGenerationIncome);
        AccountIncome item = findAccountIncome(incomes, account);
        if (item != null) {
            item.income = item.income.add(deltaDirectIncome, deltaStaticIncome, deltaDynamicIncome, deltaGenerationIncome);
        } else {
            item = new AccountIncome(account, new Income(deltaDirectIncome, deltaStaticIncome, deltaDynamicIncome, deltaGenerationIncome));
            incomes.add(item);
        }
        return item;
    }

    private void applyStaticIncomes(TreeTransaction tx, List<Account> changedAccounts, List<AccountIncome> incomes) {
        // 把直推和静态收益应用到树中，计算动态收益
        TreeSnapshot snapshot = tx.getSnapshot();
        Map<Account, BigDecimal> accountChildrenTotalStaticIncomesMap = new HashMap<>(); // 各团队leader节点排除自身外给自己贡献动态收益的节点的所有静态收益之和
        List<Account> affectedParentAccounts = new ArrayList<>(); // 可能要计算动态收益的节点.需要保持加入的顺序
        int i = 0;
        while (i < incomes.size()) {
            AccountIncome accountIncome = incomes.get(i);
            BigDecimal directIncome = accountIncome.income.getDirectIncome();
            BigDecimal staticIncome = accountIncome.income.getStaticIncome();

            Account account = accountIncome.account;
            BigDecimal recommenderDirectIncome = BigDecimal.ZERO;
            //不为空说明存在下级节点的动态收益
            if (account.getCurrentRecommenderRewardArr() != null) {
                //求和操作
                recommenderDirectIncome = Arrays.stream(account.getCurrentRecommenderRewardArr()).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            }

            //当前账户的静态收益和直推收益归入到上级账户的团队收益里面进行计算
            BigDecimal directWithStatic = staticIncome.add(recommenderDirectIncome);
            //获取上级为vip等级的账户信息
            Account parentVipAccount = getParentVipAccount(account);
            if (parentVipAccount != null) {
                log.info("static income info. parentAccount:{}, phone:{}, 静态收益:{}, 其中【个人静态收益:{}, 直接推荐收益:{}】",
                        parentVipAccount.getPhone(), account.getPhone(), directWithStatic, staticIncome, recommenderDirectIncome);
                accountChildrenTotalStaticIncomesMap.put(parentVipAccount, accountChildrenTotalStaticIncomesMap.getOrDefault(parentVipAccount, BigDecimal.ZERO).add(directWithStatic));
                if (!affectedParentAccounts.contains(parentVipAccount)) {
                    affectedParentAccounts.add(parentVipAccount);
                }

                //上级vip账户的更上一级的非根级父极节点也会获得该账户伞下的vip用户的动态收益（排除vip账户的静态收益)
                Account parent2Account = parentVipAccount.getParent();
                if (recommenderDirectIncome.compareTo(BigDecimal.ZERO) > 0 && !(parent2Account == null || parent2Account.isSystem())) {
                    log.info("static income info. parentAccount:{}, phone:{}, 静态收益:{}, 其中【个人静态收益:{}, 直接推荐收益:{}】",
                            parent2Account, parentVipAccount.getPhone(), recommenderDirectIncome, BigDecimal.ZERO, recommenderDirectIncome);
                    accountChildrenTotalStaticIncomesMap.put(parent2Account, accountChildrenTotalStaticIncomesMap.getOrDefault(parent2Account, BigDecimal.ZERO).add(recommenderDirectIncome));
                }
            }
            i++;
        }
        for (Account account : affectedParentAccounts) {
            BigDecimal subTreeTotalStaticIncomes = accountChildrenTotalStaticIncomesMap.get(account);
            if (subTreeTotalStaticIncomes == null) {
                continue;
            }
            BigDecimal sharedToParentsIncome = BigDecimal.ZERO; // 已经分享给上级们的收益
            // 如果上级是v1或者v1+，则上级有级差动态收益
            if (account.getLevel() >= AccountLevels.V1) {
                AccountLevels.LevelInfo accountLevelInfo = AccountLevels.getLevelInfo(account.getLevel());
                BigDecimal p1Income = subTreeTotalStaticIncomes.multiply(accountLevelInfo.getDividendPercentage());
                p1Income = MathUtils.min(p1Income, account.getDividendPool());
                log.info("give parent dynamic income by children static-direct incomes");
                addAccountIncome(incomes, account, BigDecimal.ZERO, BigDecimal.ZERO, p1Income, BigDecimal.ZERO); // 添加团队动态收益
                account.setDividendPoolWithSnapshot(snapshot, account.getDividendPool().subtract(p1Income));
                sharedToParentsIncome = sharedToParentsIncome.add(p1Income);

                Account parent = account.getParent();
                while (parent != null && !parent.isSystem()) {
                    // 如果V1经过若干个V1后有个祖先V2，给7%给这个V2，然后再经过若干给V2后有个祖先V3，再给10%给那个V3
                    // 上级也要分享n级的子孙静态收益带来的一些级差动态收益
                    AccountLevels.LevelInfo parentLevelInfo = AccountLevels.getLevelInfo(parent.getLevel());
                    BigDecimal p2TotalIncome = subTreeTotalStaticIncomes.multiply(parentLevelInfo.getDividendPercentage());
                    BigDecimal p2Income = p2TotalIncome.subtract(sharedToParentsIncome);
                    p2Income = MathUtils.min(p2Income, parent.getDividendPool());
                    if (p2Income.compareTo(BigDecimal.ZERO) > 0) {
                        log.info("give parent's parent remaining income by children static-direct incomes");
                        addAccountIncome(incomes, parent, BigDecimal.ZERO, BigDecimal.ZERO, p2Income, BigDecimal.ZERO); // 添加团队动态收益
                        parent.setDividendPoolWithSnapshot(snapshot, parent.getDividendPool().subtract(p2Income));
                        sharedToParentsIncome = sharedToParentsIncome.add(p2Income);
                        changedAccounts.add(parent);
                    }
                    parent = parent.getParent();
                }
                changedAccounts.add(account);
            }
        }

        // 计算平级代数收益。只向上推算4代上级
        for (int j = 0; j < affectedParentAccounts.size(); j++) {
            Account account = affectedParentAccounts.get(j);
//            if (j >= 4) {
//                break; // 目前最多向上计算4代的代数收益
//            }
            // 需要先得到account的团队动态收益，以团队动态收益为基础计算代数收益
            AccountIncome accountIncome = findAccountIncome(incomes, account);
            if (accountIncome == null) {
                continue;
            }
            Income income = accountIncome.getIncome();
            if (account.getLevel() < AccountLevels.V1) {
                continue;
            }
            // 如果本级是v1或者v1+，则上级有代数收益
            Account parent1 = account.getParent();
            if (parent1 != null && !parent1.isSystem()) {
                BigDecimal p1Income = income.getDynamicIncome().multiply(new BigDecimal("0.2"));
                p1Income = MathUtils.min(p1Income, parent1.getDividendPool());
                if (p1Income.compareTo(BigDecimal.ZERO) > 0) {
                    log.info("give upper team leader generation income");
                    addAccountIncome(incomes, parent1, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, p1Income);
                    parent1.setDividendPoolWithSnapshot(snapshot, parent1.getDividendPool().subtract(p1Income));
                    changedAccounts.add(parent1);
                }
                Account parent2 = parent1.getParent();
                if (parent2 != null && !parent2.isSystem()) {
                    BigDecimal p2Income = income.getDynamicIncome().multiply(new BigDecimal("0.1"));
                    p2Income = MathUtils.min(p2Income, parent2.getDividendPool());
                    if (p2Income.compareTo(BigDecimal.ZERO) > 0) {
                        log.info("give upper's upper team leader generation income");
                        addAccountIncome(incomes, parent2, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, p2Income);
                        parent2.setDividendPoolWithSnapshot(snapshot, parent2.getDividendPool().subtract(p2Income));
                        changedAccounts.add(parent2);
                    }
                }
            }

        }
    }

    /**
     * 获取上级为vip等级的账户信息
     *
     * @return
     */
    private Account getParentVipAccount(Account account) {
        Account parent = account.getParent();
        if (parent == null || parent.isSystem()) {
            return null; //根节点返回为空
        } else if (parent.getLevel() >= AccountLevels.V1) {
            return parent;
        } else {
            return getParentVipAccount(parent);
        }
    }

    private void getAddNewDepositStaticIncomes(TreeTransaction tx, List<Account> changedAccounts, List<AccountIncome> incomes,
                                               String accountKey, BigDecimal originalOrePool, BigDecimal depositAmount, BigDecimal intoDividendPoolAmount) throws AccountNotFoundException {
        // 更新账户充值和分红池，级别等信息，并获取 addNewDeposit 带来的静态收益
        Account account = findInTreeByKey(accountKey);
        if (account == null) {
            throw new AccountNotFoundException("account " + accountKey + " not found");
        }
        TreeSnapshot snapshot = tx.getSnapshot();

        changedAccounts.add(account);
        // 更新充值金额和个人分红池
        BigDecimal newDividendPool = originalOrePool.add(intoDividendPoolAmount);
        BigDecimal dividendPoolDelta = newDividendPool.subtract(account.getDividendPool());
        account.setDividendPoolWithSnapshot(snapshot, newDividendPool);
        account.setDepositAmountWithSnapshot(snapshot, depositAmount);
        if (dividendPoolDelta.compareTo(BigDecimal.ZERO) > 0) {
            account.setDepositedTotalWithSnapshot(snapshot, account.getDepositedTotal().add(depositAmount));
            account.setLevelWithSnapshot(snapshot, AccountLevels.getLevelOfTotalChildrenDeposited(account, account.countTotalChildrenDepositedTotal()));
        }


        // 更新account和上级各账户级别
        Account parent = account.getParent();
        while (parent != null) {
            BigDecimal childrenTotalDeposited = parent.countTotalChildrenDepositedTotal();
            int level = AccountLevels.getLevelOfTotalChildrenDeposited(parent, childrenTotalDeposited);
            if (parent.getChildren().size() < Config.v1MinChildrenCount) {
                level = 0;
            }
            if (!parent.getLevel().equals(level)) {
                parent.setLevelWithSnapshot(snapshot, level);
                changedAccounts.add(parent);
            }
            parent = parent.getParent();
        }

        storeStrategy.saveAccounts(changedAccounts);

    }


    /**
     * 有账户非第一次入金时触发
     *
     * @param accountKey             账户key
     * @param depositAmount          本次入金金额
     * @param intoDividendPoolAmount 本次充值后进入分红池的金额.本次入金对应的矿池金额
     * @param depositAgain           是否复投
     */
    public synchronized Pair<List<Account>, List<AccountIncome>> addNewDeposit(TreeTransaction tx,
                                                                               String accountKey, BigDecimal originalOrePool, BigDecimal depositAmount,
                                                                               BigDecimal intoDividendPoolAmount, boolean depositAgain) throws AccountNotFoundException {
        TreeSnapshot snapshot = tx.getSnapshot();
        List<Account> changedAccounts = new ArrayList<Account>();
        List<AccountIncome> incomes = new ArrayList<AccountIncome>();

        Account account = findInTreeByKey(accountKey);
        if (account == null) {
            throw new AccountNotFoundException("can't find account " + accountKey);
        }
        log.info("addNewDeposit({} {}, {}, {}, {}, {})", account.getKey(), account.getPhone(),
                originalOrePool, depositAmount, intoDividendPoolAmount, depositAgain);
        Account parentAccount = findInTreeByKey(account.getParentKey());
        BigDecimal maxFree = BigDecimal.ZERO;
        // 因为复投而释放个人分红池
        if (parentAccount != null && depositAgain) {
            maxFree = new BigDecimal("0.1").multiply(depositAmount);
            if (parentAccount.getDividendPool().compareTo(maxFree) < 0) {
                maxFree = parentAccount.getDividendPool();
            }
            changedAccounts.add(parentAccount);
        }


        BigDecimal newDividendPool = originalOrePool.add(intoDividendPoolAmount);
        BigDecimal dividendPoolDelta = newDividendPool.subtract(account.getDividendPool());
        boolean changedByActivateBefore = dividendPoolDelta.compareTo(BigDecimal.ZERO) == 0; // 是否orePool被之前的activateNewAccount改过

        getAddNewDepositStaticIncomes(tx, changedAccounts, incomes, accountKey, originalOrePool, depositAmount, intoDividendPoolAmount);

        if (depositAgain && maxFree.compareTo(BigDecimal.ZERO) > 0) {
            //添加直接推荐奖励的记录
            parentAccount.addRecommenderReward(new BigDecimal[]{maxFree});
            //设置矿池金额
            parentAccount.setDividendPoolWithSnapshot(snapshot, parentAccount.getDividendPool().subtract(maxFree));
            // 新下线充值时部分金额作为额度给上级释放分红池
            log.info("give parent re-deposit direct income");
            addAccountIncome(incomes, parentAccount, maxFree, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
        } else {
            log.info("addNewDeposit. userId:{}, depositAgain:{}, maxFree:{}, incomes is empty", accountKey, depositAgain, maxFree);
        }

//        applyStaticIncomes(tx, changedAccounts, incomes);

        return Pair.of(changedAccounts, incomes);
    }

    /**
     * 需要分配新的分红收益时触发，比如每天调用一次
     *
     * @param dividendIncomePercentage 分红收益占各自个人分红池比例，比如 0.75% = 0.0075
     */
    public synchronized Pair<List<Account>, List<AccountIncome>> addNewDividendIncome(final TreeTransaction tx,
                                                                                      final BigDecimal dividendIncomePercentage) {
        TreeSnapshot snapshot = tx.getSnapshot();
        List<Account> changedAccounts = new ArrayList<>();
        final List<AccountIncome> incomes = new ArrayList<>();

        // 先找到树的叶子节点，从底向上增加静态收益
        rootNode.visitTreeFromDownToTop(new AccountTreeVisitor() {

            public void visitAccount(Account account) {
                if (account.isSystem()) {
                    return;
                }
                //矿金<=0的账户不享受团队收益和静态收益
                if (account.getDividendPool().compareTo(BigDecimal.ZERO) <= 0) {
                    return;
                }
                BigDecimal incomeAmount = dividendIncomePercentage.multiply(account.getDividendPool());
                account.setDividendPoolWithSnapshot(snapshot, account.getDividendPool().subtract(incomeAmount));
                incomes.add(new AccountIncome(account, new Income(BigDecimal.ZERO, incomeAmount, BigDecimal.ZERO, BigDecimal.ZERO)));
            }
        });

        applyStaticIncomes(tx, changedAccounts, incomes);

        storeStrategy.saveAccounts(changedAccounts);
        return Pair.of(changedAccounts, incomes);
    }

    /**
     * 系统结算后，重置推荐奖励：currentRecommenderRewardArr
     */
    public synchronized List<Account> resetCurrentRecommenderRewardArr(final TreeTransaction tx) {
        TreeSnapshot snapshot = tx.getSnapshot();
        List<Account> changedAccounts = new ArrayList<>();
        // 先找到树的叶子节点，从底向上增加静态收益
        rootNode.visitTreeFromDownToTop(new AccountTreeVisitor() {
            public void visitAccount(Account account) {
                //不为空说明存在下级节点的直接推荐收益
                if (account.getCurrentRecommenderRewardArr() != null) {
                    account.resetCurrentRecommenderRewardArr(snapshot);
                    changedAccounts.add(account);
                }
            }
        });

        storeStrategy.saveAccounts(changedAccounts);
        return changedAccounts;
    }


    @Override
    public String toString() {
        return rootNode.toTreeString(0);
    }
}
